package com.idanchuang.count.service.impl

import com.idanchuang.component.base.exception.exception.BusinessException
import com.idanchuang.count.BaseCustomSpecification
import com.idanchuang.count.config.IntegrationTestConfig
import com.idanchuang.count.service.MsgUnreadCountService
import com.idanchuang.user.count.service.api.request.command.read.*
import com.idanchuang.user.count.service.api.request.query.read.BatchUserUnreadMsgCountQuery
import com.idanchuang.user.count.service.api.request.query.read.UserMsgIfReadBatchQuery
import com.idanchuang.user.count.service.api.request.query.read.UserUnreadMsgCountQuery
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.redis.core.StringRedisTemplate
import org.springframework.test.context.ContextConfiguration
import org.testcontainers.spock.Testcontainers
import spock.lang.Subject

/**
 * @author Richard_yyf
 * @version 1.0 2021/7/8
 */
@ContextConfiguration(
        initializers = IntegrationTestConfig.IntegrationTestInitializer.class,
        classes = [IntegrationTestConfig.class])
@Testcontainers
@Subject(MsgUnreadCountServiceImpl)
class MsgUnreadCountServiceImplTest extends BaseCustomSpecification {

    @Autowired
    private StringRedisTemplate stringRedisTemplate

    @Autowired
    private MsgUnreadCountService msgUnreadCountService

    def cleanup() {
        // runs after every feature method
        // clean
        Set<String> keys = stringRedisTemplate.keys("msg:*")
        keys.addAll(stringRedisTemplate.keys("count:*"))
        keys.addAll(stringRedisTemplate.keys("rt:*"))
        println("delete keys: " + keys.toString())
        stringRedisTemplate.delete(keys)
    }

    static def bizCode = "bizA"
    static def bizId = 1

    def "AddUserMsg"() {

        given:
        def addUserMsgCmd = new AddUserMsgCommand(
                bizCode: bizCode,
                userCode : 100,
                scene : "sceneA",
                msgId : "msg0001"
        )
        def query = new UserUnreadMsgCountQuery(
                bizCode: bizCode,
                userCode : 100,
                scene : "sceneA"
        )
        when:
        msgUnreadCountService.addUserMsg(addUserMsgCmd)

        then:
        1 == msgUnreadCountService.queryUnreadMsgCount(query).count
    }

    def "AddUserMsgInAsyncBatch"() {

        given:
        def addCmdList = []
        1.upto(100, {
            addCmdList.add(new AddUserMsgCommand(
                    bizCode: bizCode,
                    userCode : 100,
                    scene : "sceneA",
                    msgId : "msg000${it}"
            ))
        })
        1.upto(100, {
            addCmdList.add(new AddUserMsgCommand(
                    bizCode: bizCode,
                    userCode : 101,
                    scene : "sceneA",
                    msgId : "msg000${it}"
            ))
        })

        when:
        msgUnreadCountService.addUserMsgInAsyncBatch(addCmdList)

        then:
        100 == msgUnreadCountService.queryUnreadMsgCount(new UserUnreadMsgCountQuery(bizCode: bizCode, userCode : 100, scene : "sceneA")).count
        100 == msgUnreadCountService.queryUnreadMsgCount(new UserUnreadMsgCountQuery(bizCode: bizCode, userCode : 101, scene : "sceneA")).count
    }

    def "BatchAddUserMsg"() {
        given:
        def batchAdd = new BatchAddUserMsgCommand(
                bizCode: bizCode,
                userCodeList : 101..105,
                scene : "sceneA",
                msgId : "msg00001"
        )
        when:
        msgUnreadCountService.batchAddUserMsg(batchAdd)

        then:
        1 == msgUnreadCountService.queryUnreadMsgCount(new UserUnreadMsgCountQuery(bizCode: bizCode, userCode : 101, scene : "sceneA")).count
        1 == msgUnreadCountService.queryUnreadMsgCount(new UserUnreadMsgCountQuery(bizCode: bizCode, userCode : 102, scene : "sceneA")).count
        1 == msgUnreadCountService.queryUnreadMsgCount(new UserUnreadMsgCountQuery(bizCode: bizCode, userCode : 103, scene : "sceneA")).count
        1 == msgUnreadCountService.queryUnreadMsgCount(new UserUnreadMsgCountQuery(bizCode: bizCode, userCode : 104, scene : "sceneA")).count
        1 == msgUnreadCountService.queryUnreadMsgCount(new UserUnreadMsgCountQuery(bizCode: bizCode, userCode : 105, scene : "sceneA")).count
    }

    def "AddSysMsg"() {
        given:
        def addCmd = new AddSysMsgCommand(
                bizCode: bizCode,
                scene : "sceneA",
                msgId : "msg00001"
        )

        when:
        println("command timestamp: " + addCmd.timeStamp)
        msgUnreadCountService.addSysMsg(addCmd)

        then:
        1 == msgUnreadCountService.queryUnreadMsgCount(new UserUnreadMsgCountQuery(bizCode: bizCode, userCode : 100, scene : "sceneA")).count
    }

    def "RemoveSysMsg"() {
        given:
        def addCmd = new AddSysMsgCommand(
                bizCode: bizCode,
                scene : "sceneA",
                msgId : "msg00001"
        )
        def rmCmd = new RemoveSysMsgCommand(
                bizCode: bizCode,
                scene : "sceneA",
                msgId : "msg00001"
        )

        when:
        println("command timestamp: " + addCmd.timeStamp)
        msgUnreadCountService.addSysMsg(addCmd)
        int before = msgUnreadCountService.queryUnreadMsgCount(new UserUnreadMsgCountQuery(bizCode: bizCode, userCode : 101, scene : "sceneA")).count;
        msgUnreadCountService.removeSysMsg(rmCmd)
        int after = msgUnreadCountService.queryUnreadMsgCount(new UserUnreadMsgCountQuery(bizCode: bizCode, userCode : 101, scene : "sceneA")).count;

        then:
        1 == before
        0 == after
    }

    def "RemoveUserMsg"() {
        given:
        def addUserMsgCmd = new AddUserMsgCommand(
                bizCode: bizCode,
                userCode : 100,
                scene : "sceneA",
                msgId : "msg0001"
        )
        def rmUserMsgCmd = new RemoveUserMsgCommand(
                bizCode: bizCode,
                userCode : 100,
                scene : "sceneA",
                msgIdList : ["msg0001"]
        )
        def query = new UserUnreadMsgCountQuery(
                bizCode: bizCode,
                userCode : 100,
                scene : "sceneA"
        )
        when:
        msgUnreadCountService.addUserMsg(addUserMsgCmd)
        def before = msgUnreadCountService.queryUnreadMsgCount(query).count
        msgUnreadCountService.removeUserMsg(rmUserMsgCmd)
        def after = msgUnreadCountService.queryUnreadMsgCount(query).count

        then:
        1 == before
        0 == after
    }

    def "test_BatchQueryUnreadMsgCount"() {
        given:
        def addSysCmdA = new AddSysMsgCommand(
                bizCode: bizCode,
                scene : "sceneA",
                msgId : "msg00001"
        )
        def addUserMsgCmdA = new AddUserMsgCommand(
                bizCode: bizCode,
                userCode : 100,
                scene : "sceneA",
                msgId : "msg0001"
        )
        def addUserMsgCmdA2 = new AddUserMsgCommand(
                bizCode: bizCode,
                userCode : 100,
                scene : "sceneA",
                msgId : "msg0002"
        )
        def addSysCmdB = new AddSysMsgCommand(
                bizCode: bizCode,
                scene : "sceneB",
                msgId : "msg00001"
        )
        def addUserMsgCmdB = new AddUserMsgCommand(
                bizCode: bizCode,
                userCode : 100,
                scene : "sceneB",
                msgId : "msg0001"
        )

        when:
        msgUnreadCountService.addSysMsg(addSysCmdA)
        msgUnreadCountService.addSysMsg(addSysCmdB)
        msgUnreadCountService.addUserMsg(addUserMsgCmdA)
        msgUnreadCountService.addUserMsg(addUserMsgCmdA2)
        msgUnreadCountService.addUserMsg(addUserMsgCmdB)

        def batchQuery = new BatchUserUnreadMsgCountQuery(
                userCode: 100,
                bizCode: bizCode,
                scenes: ["sceneA", "sceneA", "sceneB"]
        )
        def countDTO = msgUnreadCountService.batchQueryUnreadMsgCount(batchQuery)

        then:
        countDTO.sceneCountMap.size() == 2
        countDTO.sceneCountMap['sceneA'] == 3
        countDTO.sceneCountMap['sceneB'] == 2
        countDTO.totalCount == 5
    }

    def "QueryUnreadMsgCount"() {
        given:
        def addSysCmd = new AddSysMsgCommand(
                bizCode: bizCode,
                scene : "sceneA",
                msgId : "msg00001"
        )
        def addUserMsgCmd = new AddUserMsgCommand(
                bizCode: bizCode,
                userCode : 100,
                scene : "sceneA",
                msgId : "msg0001"
        )

        when:
        msgUnreadCountService.addSysMsg(addSysCmd)
        msgUnreadCountService.addUserMsg(addUserMsgCmd)

        then:
        2 == msgUnreadCountService.queryUnreadMsgCount(new UserUnreadMsgCountQuery(bizCode: bizCode, userCode : 100, scene : "sceneA")).count;
    }

    def "ReadAll"() {
        given:
        def addSysCmd = new AddSysMsgCommand(
                bizCode: bizCode,
                scene : "sceneA",
                msgId : "msg00001"
        )
        def addUserMsgCmd = new AddUserMsgCommand(
                bizCode: bizCode,
                userCode : 100,
                scene : "sceneA",
                msgId : "msg0001"
        )
        def readAllCmd = new UserMsgAllReadCommand(
                bizCode: bizCode,
                userCode : 100,
                scene : "sceneA"
        )
        when:
        msgUnreadCountService.addSysMsg(addSysCmd)
        msgUnreadCountService.addUserMsg(addUserMsgCmd)
        int before = msgUnreadCountService.queryUnreadMsgCount(new UserUnreadMsgCountQuery(bizCode: bizCode, userCode : 100, scene : "sceneA")).count
        msgUnreadCountService.readAll(readAllCmd)
        int after = msgUnreadCountService.queryUnreadMsgCount(new UserUnreadMsgCountQuery(bizCode: bizCode, userCode: 100, scene: "sceneA")).count

        then:
        2 == before
        0 == after
    }

    def "ReadAllInAsyncBatch"() {
        given:
        def addSysCmd = new AddSysMsgCommand(
                bizCode: bizCode,
                scene : "sceneA",
                msgId : "msg00001"
        )
        def addUserMsgCmd1 = new AddUserMsgCommand(
                bizCode: bizCode,
                userCode : 101,
                scene : "sceneA",
                msgId : "msg0001"
        )
        def addUserMsgCmd2 = new AddUserMsgCommand(
                bizCode: bizCode,
                userCode : 102,
                scene : "sceneA",
                msgId : "msg0001"
        )
        def readAllCmd1 = new UserMsgAllReadCommand(
                bizCode: bizCode,
                userCode : 101,
                scene : "sceneA"
        )
        def readAllCmd2 = new UserMsgAllReadCommand(
                bizCode: bizCode,
                userCode : 102,
                scene : "sceneA"
        )
        when:
        msgUnreadCountService.addSysMsg(addSysCmd)
        msgUnreadCountService.addUserMsg(addUserMsgCmd1)
        msgUnreadCountService.addUserMsg(addUserMsgCmd2)
        int before1 = msgUnreadCountService.queryUnreadMsgCount(new UserUnreadMsgCountQuery(bizCode: bizCode, userCode: 101, scene: "sceneA")).count
        int before2 = msgUnreadCountService.queryUnreadMsgCount(new UserUnreadMsgCountQuery(bizCode: bizCode, userCode: 102, scene: "sceneA")).count
        msgUnreadCountService.readAllInAsyncBatch([readAllCmd1, readAllCmd2])
        int after1 = msgUnreadCountService.queryUnreadMsgCount(new UserUnreadMsgCountQuery(bizCode: bizCode, userCode: 101, scene: "sceneA")).count
        int after2 = msgUnreadCountService.queryUnreadMsgCount(new UserUnreadMsgCountQuery(bizCode: bizCode, userCode: 102, scene: "sceneA")).count

        then:
        2 == before1
        2 == before2
        0 == after1
        0 == after2
    }

    def "batchQueryUserMsgIfRead"() {
        given: "sys:1, user:2, totalUnreadCount: 3"
        def addSysCmd = new AddSysMsgCommand(
                bizCode: bizCode,
                scene : "sceneA",
                msgId : "sysMsg1"
        )
        def addUserMsgCmd1 = new AddUserMsgCommand(
                bizCode: bizCode,
                userCode : 101,
                scene : "sceneA",
                msgId : "userMsg1"
        )
        def addUserMsgCmd2 = new AddUserMsgCommand(
                bizCode: bizCode,
                userCode : 101,
                scene : "sceneA",
                msgId : "userMsg2"
        )

        def sourceMsgNo1 = [addSysCmd.msgId, addUserMsgCmd1.msgId, addUserMsgCmd2.msgId, "notExist1", "notExist2"]
        def ifReadQuery1 = new UserMsgIfReadBatchQuery(
                bizCode: bizCode, userCode: 101, scene: "sceneA", msgNos: sourceMsgNo1)

        def sourceMsgNo2 = []
        def ifReadQuery2 = new UserMsgIfReadBatchQuery(
                bizCode: bizCode, userCode: 101, scene: "sceneA", msgNos: sourceMsgNo2)

        def sourceMsgNo3 = ["notExist1", "notExist2"]
        def ifReadQuery3 = new UserMsgIfReadBatchQuery(
                bizCode: bizCode, userCode: 101, scene: "sceneA", msgNos: sourceMsgNo3)

        when:
        msgUnreadCountService.addSysMsg(addSysCmd)
        msgUnreadCountService.addUserMsg(addUserMsgCmd1)
        msgUnreadCountService.addUserMsg(addUserMsgCmd2)

        def targetUnreadMsgNos1 = msgUnreadCountService.batchQueryUserMsgIfRead(ifReadQuery1)
        def targetUnreadMsgNos2 = msgUnreadCountService.batchQueryUserMsgIfRead(ifReadQuery2)
        def targetUnreadMsgNos3 = msgUnreadCountService.batchQueryUserMsgIfRead(ifReadQuery3)

        then:
        targetUnreadMsgNos1.size() == 3
        targetUnreadMsgNos2.size() == 0
        targetUnreadMsgNos3.size() == 0
        targetUnreadMsgNos1.containsAll([addSysCmd.msgId, addUserMsgCmd1.msgId, addUserMsgCmd2.msgId])

    }

    def "batchQueryUserMsgIfRead_query_over_limit"() {
        given: "query over limit"

        def ifReadQuery1 = new UserMsgIfReadBatchQuery(
                bizCode: bizCode, userCode: 101, scene: "sceneA", msgNos: ["1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21"])

        when:
        msgUnreadCountService.batchQueryUserMsgIfRead(ifReadQuery1)

        then:
        thrown(BusinessException)
    }

}
